package com.cq.smartelebicycle.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import com.cq.smartelebicycle.R;

public class SpeedView extends View {
	

	private static final int REQUEST_UI = 0;
	private float mWidth;
	private float mHeight;
	private float leftEdge;
	private float topEdge;
	
	private float rX;
	private float rY;
	
	private float mLargeRadius;
	
	private final int LARGE_RES_COUNT = 13;
	private DialDrawable[] mLargeDials;
	private int largeIndex = 0;
	private int[] largeDialsRes = new int[] {R.drawable.dabiaopan, R.drawable.dabiaopan001, R.drawable.dabiaopan002, R.drawable.dabiaopan003, 
											 R.drawable.dabiaopan004, R.drawable.dabiaopan005, R.drawable.dabiaopan006, R.drawable.dabiaopan007,
											 R.drawable.dabiaopan008, R.drawable.dabiaopan009, R.drawable.dabiaopan010, R.drawable.dabiaopan011, 
											 R.drawable.dabiaopan012};
	
	private final int SMALL_RES_COUNT = 13;
	private DialDrawable[] mSmallDials;
	private int smallIndex = 0;
	private int[] smallDialsRes = new int[] {R.drawable.xiaobiaopan, R.drawable.xiaobiaopan001, R.drawable.xiaobiaopan002, R.drawable.xiaobiaopan003, 
											 R.drawable.xiaobiaopan004, R.drawable.xiaobiaopan005, R.drawable.xiaobiaopan006, R.drawable.xiaobiaopan007,
											 R.drawable.xiaobiaopan008, R.drawable.xiaobiaopan009, R.drawable.xiaobiaopan010, R.drawable.xiaobiaopan011, 
											 R.drawable.xiaobiaopan012};
	
	private final float RADIU_SCALE = 0.5f;
	private float mSmallRadius;
	
	
	private final float radian = (float) (Math.PI / 180);
	
	private final float degrees = (float) (180 / Math.PI);
	
	
	private final float LARGE_GUILD_SCALE = 420f / 538f;
	private final float LARGE_GUILD_WIDTH = 1f;
	private Drawable mLargeGuide;
	
	private final float SMALL_GUILD_SCALE = 4f / 5f;
	private final float SMALL_GUILD_WIDTH = 1f / 5f;
	private Drawable mSmallGuide;
	
	private float largeRadian;
	private float smallRadian;
	private boolean mChanged;
	
	@SuppressLint("HandlerLeak")
	private Handler mHandler = new Handler() {
		
		public void handleMessage(Message msg) {
			invalidate();
		}
		
	};
	
	public SpeedView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpeedView);
		Drawable large = a.getDrawable(R.styleable.SpeedView_largeDial);
		Drawable small = a.getDrawable(R.styleable.SpeedView_smallDial);
		mLargeDials = new DialDrawable[LARGE_RES_COUNT];
		if (large != null) {
			mLargeDials[largeIndex] = new DialDrawable();
			mLargeDials[largeIndex].drawable = large;
		}
		mSmallDials = new DialDrawable[SMALL_RES_COUNT];
		if (small != null) {
			mSmallDials[smallIndex] = new DialDrawable();
			mSmallDials[smallIndex].drawable = small;
		}
		mLargeGuide = a.getDrawable(R.styleable.SpeedView_largeGuide);
		mSmallGuide = a.getDrawable(R.styleable.SpeedView_smallGuide);
		leftEdge = a.getFloat(R.styleable.SpeedView_leftEdge, 0);
		largeRadian = -15 * radian;
		smallRadian = 15 * radian;
		a.recycle();
	}

	public void setSpeed(float speed) {
		largeRadian = (float) ((speed - 2.5) / 30 * Math.PI);
		largeIndex = getLargeIndexBySpeed(speed);
		smallRadian = (float) ((speed - (int) speed) * 12 * 15 * Math.PI / 18 / 12 + Math.PI / 12);
		smallIndex = getSmallIndexBySpeed(speed);
		mHandler.removeMessages(REQUEST_UI);
		mHandler.sendEmptyMessageDelayed(REQUEST_UI, 200);
	}
	
	private int getSmallIndexBySpeed(float speed) {
		// TODO Auto-generated method stub
		speed = speed - (int) speed;
		if (speed <= 0) {
			return 0;
		} else {
			int i = (int) (speed * 12);
			if (i == 0) {
				return 1;
			} else if (i >= 11) {
				return SMALL_RES_COUNT - 1;
			}
			return i + 1;
		}
		
	}

	private int getLargeIndexBySpeed(float speed) {
		// TODO Auto-generated method stub
		if (speed <= 0) {
			return 0;
		} else if (speed < 5) {
			return 1;
		} else if (speed >= 30) {
			return LARGE_RES_COUNT - 1;
		} else {
			return (int) (speed / 2.5);
		}
	}
	
	public void setScaleView(float leftEdge) {
		this.leftEdge = leftEdge;
		for (int i = 0; i < LARGE_RES_COUNT; i++) {
			if (mLargeDials[i] != null) {
				mLargeDials[i].isSetBounds = false;
			}
		}
		for (int i = 0; i < SMALL_RES_COUNT; i++) {
			if (mSmallDials[i] != null) {
				mSmallDials[i].isSetBounds = false;
			}
		}
	}
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		boolean changed = mChanged;
		if (changed) {
			mChanged = false;
			setLargeGuildBounds();
			setSmallGuildBounds();
		}
		setDialBoundsIfNeed();
		mLargeDials[largeIndex].drawable.draw(canvas);
		mSmallDials[smallIndex].drawable.draw(canvas);
		drawLargeGuild(canvas);
		drawSmallGuild(canvas);
		
	}
	
	private void setDialBoundsIfNeed() {
		int left = (int) (leftEdge);
		int top = (int) (topEdge);
		int right = (int) (leftEdge + 2* mLargeRadius);
		int bottom = (int) (mHeight - topEdge);
		
		if (mLargeDials[largeIndex] == null) {
			mLargeDials[largeIndex] = new DialDrawable();
			mLargeDials[largeIndex].drawable = getContext().getResources().getDrawable(largeDialsRes[largeIndex]);
		}
		if (!mLargeDials[largeIndex].isSetBounds) {
			mLargeDials[largeIndex].drawable.setBounds(left, top, right, bottom);
			mLargeDials[largeIndex].isSetBounds = true;
		}
		if (mSmallDials[smallIndex] == null) {
			mSmallDials[smallIndex] = new DialDrawable();
			mSmallDials[smallIndex].drawable = getContext().getResources().getDrawable(smallDialsRes[smallIndex]);
		}
		if (!mSmallDials[smallIndex].isSetBounds) {
			mSmallDials[smallIndex].drawable.setBounds((int) (rX - mSmallRadius * Math.cos(radian*15)),(int)(rY - mSmallRadius),
					(int) (rX + mSmallRadius * Math.cos(radian*15)), (int) (rY - mSmallRadius * Math.sin(radian*15)));
			mSmallDials[smallIndex].isSetBounds = true;
		}
	}
	
	private void setSmallGuildBounds() {
		// TODO Auto-generated method stub
		float scale = (float) mSmallGuide.getIntrinsicHeight() / (float) mSmallGuide.getIntrinsicWidth();
		int left = (int) (rX - SMALL_GUILD_SCALE * mSmallRadius);
		int top = (int) (rY - mSmallRadius * SMALL_GUILD_WIDTH * scale / 2);
		int right = (int) (rX - SMALL_GUILD_SCALE * mSmallRadius + SMALL_GUILD_WIDTH * mSmallRadius);
		int bottom = (int) (rY + mSmallRadius * SMALL_GUILD_WIDTH * scale / 2);
		mSmallGuide.setBounds(left, top, right, bottom);
	}

	private void drawLargeGuild(Canvas canvas) {
		// TODO Auto-generated method stub
		canvas.save();
		canvas.rotate(largeRadian * degrees, rX, rY);
		mLargeGuide.draw(canvas);
		canvas.restore();
	}

	private void setLargeGuildBounds() {
		// TODO Auto-generated method stub
		float scale = (float) mLargeGuide.getIntrinsicHeight() / (float) mLargeGuide.getIntrinsicWidth();
		int left = (int) (rX - LARGE_GUILD_SCALE * mLargeRadius * LARGE_GUILD_WIDTH);
		int top = (int) (rY - scale * mLargeRadius / 2);
		int right = (int) (rX - LARGE_GUILD_SCALE * mLargeRadius * LARGE_GUILD_WIDTH + mLargeRadius);
		int bottom = (int) (rY + scale * mLargeRadius / 2);
		mLargeGuide.setBounds(left, top, right, bottom);
	}

	private void drawSmallGuild(Canvas canvas) {
		// TODO Auto-generated method stub
		canvas.save();
		canvas.rotate(smallRadian * degrees, rX, rY);
		mSmallGuide.draw(canvas);
		canvas.restore();
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		// TODO Auto-generated method stub
		super.onSizeChanged(w, h, oldw, oldh);
		mChanged = true;
		mWidth = getWidth();
		mHeight = getHeight();
		if (mLargeDials[largeIndex] == null) {
			mLargeDials[largeIndex].drawable = getContext().getResources().getDrawable(largeDialsRes[largeIndex]);
		}
		float scale = (float) mLargeDials[largeIndex].drawable.getIntrinsicWidth() / (float)mLargeDials[largeIndex].drawable.getIntrinsicHeight();
		if (leftEdge == 0) {
			if (scale * mHeight < mWidth) {
				topEdge = 0;
				leftEdge = (mWidth - mHeight * scale) / 2;
			} else {
				leftEdge = 0;
				topEdge = (scale * mHeight - mWidth) / (2 * scale);
			}
		} else {
			if (scale * mHeight - mWidth < 0) {
				leftEdge = Math.max(leftEdge, (mWidth - scale * mHeight) /2);
			}
			topEdge = (scale * mHeight - mWidth + 2 * leftEdge) / (2 * scale);
		}
		mLargeRadius = (mWidth - 2 * leftEdge) / 2;
		rX = mWidth / 2;
		rY = topEdge + mLargeRadius;
		mSmallRadius = RADIU_SCALE * mLargeRadius;
	}
	
	class DialDrawable {
		Drawable drawable;
		boolean isSetBounds;
	}

}
